package com.team9.fitness.service;

import com.zrdds.simpleinterface.DDSIF;
import com.zrdds.domain.DomainParticipant;
import com.zrdds.domain.DomainParticipantFactory;
import com.zrdds.infrastructure.ReturnCode_t;
import com.zrdds.infrastructure.BytesDataWriter;
import com.zrdds.infrastructure.BytesTypeSupport;
import com.zrdds.publication.DataWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import java.util.Set;
import java.util.HashSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
import java.io.File;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;

/**
 * ZRDDS管理器服务
 * 负责ZRDDS中间件的初始化、连接管理和基本操作
 */
@Service
public class ZRDDSManagerService {

    private static final Logger log = LoggerFactory.getLogger(ZRDDSManagerService.class);

    @Value("${zrdds.domain-id:0}")
    private int domainId;

    @Value("${zrdds.participant-id:1}")
    private int participantId;

    @Value("${zrdds.qos-profile:udp_dp}")
    private String qosProfile;

    @Value("${zrdds.qos-file:ZRDDS_QOS_PROFILES.xml}")
    private String qosFile;

    private boolean initialized = false;
    private DomainParticipant domainParticipant;
    private final Set<String> subscribedTopics = ConcurrentHashMap.newKeySet();

    // 存储主题和数据写入器的映射
    private final Map<String, BytesDataWriter> dataWriters = new ConcurrentHashMap<>();

    // 使用回调接口避免循环依赖
    private DataReceivedCallback dataReceivedCallback;

    /**
     * 初始化ZRDDS
     */
    @PostConstruct
    public void initialize() {
        try {
            log.info("开始初始化ZRDDS中间件...");

            // 加载ZRDDS库
            System.loadLibrary("ZRDDS_JAVA");

            // 获取QoS配置文件路径
            String qosFilePath = getQoSFilePath();

            // 初始化ZRDDS中间件
            DomainParticipantFactory factory = DDSIF.init(qosFilePath, "default");
            if (factory == null) {
                log.error("ZRDDS中间件初始化失败.");
                throw new RuntimeException("ZRDDS中间件初始化失败");
            }
            log.info("ZRDDS中间件初始化成功，使用QoS文件: {}，QoS配置: {}", qosFilePath, "default");

            // 创建域参与者
            domainParticipant = DDSIF.create_dp(domainId, qosProfile);
            if (domainParticipant == null) {
                throw new RuntimeException("创建域参与者失败");
            }

            initialized = true;
            log.info("ZRDDS中间件初始化成功 - DomainId: {}, ParticipantId: {}, QosProfile: {}",
                    domainId, participantId, qosProfile);

        } catch (Exception e) {
            log.error("ZRDDS中间件初始化失败", e);
            throw new RuntimeException("ZRDDS初始化失败", e);
        }
    }

    /**
     * 销毁ZRDDS资源
     */
    @PreDestroy
    public void destroy() {
        try {
            if (domainParticipant != null) {
                // 清理域参与者
                domainParticipant = null;
            }

            // 清理ZRDDS中间件
            DDSIF.Finalize();

            initialized = false;
            log.info("ZRDDS资源已清理");
        } catch (Exception e) {
            log.error("清理ZRDDS资源失败", e);
        }
    }

    /**
     * 检查是否已初始化
     */
    public boolean isInitialized() {
        return initialized && domainParticipant != null;
    }

    /**
     * 获取域参与者
     */
    public DomainParticipant getDomainParticipant() {
        return domainParticipant;
    }

    /**
     * 获取已订阅的主题
     */
    public Set<String> getSubscribedTopics() {
        return new HashSet<>(subscribedTopics);
    }

    /**
     * 添加订阅主题
     */
    public void addSubscribedTopic(String topicName) {
        subscribedTopics.add(topicName);
        log.info("添加订阅主题: {}", topicName);
    }

    /**
     * 移除订阅主题
     */
    public void removeSubscribedTopic(String topicName) {
        subscribedTopics.remove(topicName);
        log.info("移除订阅主题: {}", topicName);
    }

    /**
     * 创建或获取主题发布者
     */
    private BytesDataWriter createOrGetTopicPublisher(String topicName) {
        return dataWriters.computeIfAbsent(topicName, name -> {
            try {
                log.info("正在创建主题发布者: {}", name);

                // 使用ZRDDS的简化接口创建主题发布者
                // 使用BytesTypeSupport作为数据类型，使用默认QoS配置
                DataWriter writer = DDSIF.pub_topic(domainParticipant, name,
                        BytesTypeSupport.get_instance(), "reliable", null);

                if (writer == null) {
                    log.error("创建主题发布者失败: {}", name);
                    return null;
                }

                // 转换为BytesDataWriter
                BytesDataWriter bytesWriter = (BytesDataWriter) writer;
                if (bytesWriter == null) {
                    log.error("转换BytesDataWriter失败: {}", name);
                    return null;
                }

                log.info("成功创建主题发布者: {}", name);
                return bytesWriter;
            } catch (Exception e) {
                log.error("创建主题发布者失败: {}", name, e);
                return null;
            }
        });
    }

    /**
     * 发布数据到指定主题
     */
    public boolean publishData(String topicName, String data) {
        if (!isInitialized()) {
            log.warn("ZRDDS未初始化，无法发布数据");
            return false;
        }

        try {
            // 确保主题发布者已创建
            BytesDataWriter dataWriter = createOrGetTopicPublisher(topicName);
            if (dataWriter == null) {
                log.error("无法获取主题发布者: {}", topicName);
                // 尝试重新创建主题发布者
                dataWriters.remove(topicName);
                dataWriter = createOrGetTopicPublisher(topicName);
                if (dataWriter == null) {
                    log.error("重新创建主题发布者仍然失败: {}", topicName);
                    return false;
                }
            }

            // 使用ZRDDS的BytesWrite接口发布数据
            byte[] dataBytes = data.getBytes("UTF-8");
            ReturnCode_t result = DDSIF.BytesWrite(domainId, topicName, dataBytes, dataBytes.length);

            if (result == ReturnCode_t.RETCODE_OK) {
                log.info("发布数据到主题 {}: {}", topicName, data);

                // 实现自发自用：发布后立即传递给数据监听器处理
                if (dataReceivedCallback != null) {
                    dataReceivedCallback.onDataReceived(topicName, data);
                }

                return true;
            } else {
                log.error("发布数据失败: topic={}, returnCode={}", topicName, result);
                return false;
            }
        } catch (Exception e) {
            log.error("发布数据失败: topic={}, data={}", topicName, data, e);
            return false;
        }
    }

    /**
     * 强制重新创建主题发布者（用于故障恢复）
     */
    public boolean recreateTopicPublisher(String topicName) {
        try {
            log.info("强制重新创建主题发布者: {}", topicName);
            dataWriters.remove(topicName);
            BytesDataWriter newWriter = createOrGetTopicPublisher(topicName);
            return newWriter != null;
        } catch (Exception e) {
            log.error("重新创建主题发布者失败: {}", topicName, e);
            return false;
        }
    }

    /**
     * 检查主题发布者状态
     */
    public boolean isTopicPublisherHealthy(String topicName) {
        BytesDataWriter writer = dataWriters.get(topicName);
        return writer != null;
    }

    /**
     * 订阅主题
     */
    public boolean subscribeTopic(String topicName) {
        if (!isInitialized()) {
            log.warn("ZRDDS未初始化，无法订阅主题");
            return false;
        }

        try {
            // 使用ZRDDS的简化接口订阅主题
            // 这里使用默认的TypeSupport和QoS配置
            // 由于简化接口的限制，我们使用基本的订阅逻辑
            addSubscribedTopic(topicName);
            log.info("成功订阅主题: {}", topicName);
            return true;
        } catch (Exception e) {
            log.error("订阅主题失败: {}", topicName, e);
            return false;
        }
    }

    /**
     * 取消订阅主题
     */
    public boolean unsubscribeTopic(String topicName) {
        if (!isInitialized()) {
            log.warn("ZRDDS未初始化，无法取消订阅主题");
            return false;
        }

        try {
            removeSubscribedTopic(topicName);
            log.info("成功取消订阅主题: {}", topicName);
            return true;
        } catch (Exception e) {
            log.error("取消订阅主题失败: {}", topicName, e);
            return false;
        }
    }

    /**
     * 设置数据接收回调
     */
    public void setDataReceivedCallback(DataReceivedCallback callback) {
        this.dataReceivedCallback = callback;
    }

    /**
     * 获取QoS配置文件路径
     */
    private String getQoSFilePath() {
        try {
            // 首先尝试使用项目根目录的文件（避免classpath路径问题）
            String projectRoot = System.getProperty("user.dir");
            String rootPath = projectRoot + File.separator + "ZRDDS_QOS_PROFILES.xml";
            File rootFile = new File(rootPath);
            if (rootFile.exists()) {
                log.info("使用项目根目录的QoS配置文件: {}", rootPath);
                return rootPath;
            }

            // 尝试使用lib目录下的文件
            String libPath = projectRoot + File.separator + "lib" + File.separator + "ZRDDS_QOS_PROFILES.xml";
            File libFile = new File(libPath);
            if (libFile.exists()) {
                log.info("使用lib目录的QoS配置文件: {}", libPath);
                return libPath;
            }

            // 最后尝试从classpath获取
            if (qosFile.startsWith("classpath:")) {
                String resourcePath = qosFile.substring("classpath:".length());
                java.net.URL resourceUrl = getClass().getClassLoader().getResource(resourcePath);
                if (resourceUrl != null) {
                    String filePath = resourceUrl.getPath();
                    // 处理URL编码问题
                    if (filePath.contains("%20")) {
                        filePath = URLDecoder.decode(filePath, StandardCharsets.UTF_8);
                    }

                    // 检查文件是否存在
                    File classpathFile = new File(filePath);
                    if (classpathFile.exists()) {
                        log.info("从classpath获取QoS配置文件: {}", filePath);
                        return filePath;
                    } else {
                        log.warn("classpath文件不存在: {}", filePath);
                    }
                } else {
                    log.warn("无法从classpath获取QoS配置文件: {}", resourcePath);
                }
            }

            log.error("无法找到QoS配置文件，尝试的路径: {}, {}", rootPath, libPath);
            throw new RuntimeException("无法找到QoS配置文件");

        } catch (Exception e) {
            log.error("获取QoS配置文件路径失败", e);
            throw new RuntimeException("获取QoS配置文件路径失败", e);
        }
    }
}
